package com.trace.util;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by denglw on 2020/1/14.<br/>
 * Desc: 栅栏
 * 栅栏通常阻塞一系列线程，当所有需要的线程都达到栅栏位置，才能继续执行。所以，栅栏可以理解为等待其他的线程到达对应的位置，在一起执行。
 * 在做一些并发测试的时候，有时候需要所有线程都执行到相应的位置，让它们同时执行。
 * 而且栅栏是可以重复利用的，当栅栏开放后，栅栏会进行重置，然后对后续的线程进行拦截。
 * 如果await调用超时，或者await的线程被中断，栅栏就被认为是打破了，所有await的线程都会中止并且抛出BrokenBarrierException。
 * 如果成功通过栅栏，那么await将为每个线程返回一个唯一的到达索引号，我们可以通过索引来选举一个领导线程。并在下一次循环中，通过领导线程执行一些特殊工作。
 * <p>
 * 闭锁初看跟栅栏非常相似，它们作为工具类，都能作为屏障，等待线程执行到一定的地方。
 * 闭锁跟栅栏的区别，就是闭锁是一次性的，当闭锁完全打开后就不能关闭了。
 * 栅栏打开之后，放行等待之后，栅栏就被重置，等待下一次开启。闭锁使用countDown()的时候，线程不会阻塞，继续运行。
 * 栅栏没有类似的countDown()方法，使用await()的时候，还需要等待的线程数-1，直到需要等待的线程数为0的时候，栅栏打开。
 */
public class BarrierTest {
    private static CyclicBarrier barrier = new CyclicBarrier(5);

    public static void main(String[] args) {
        EatChickenPlayer a = new EatChickenPlayer("a", 3000L);
        EatChickenPlayer b = new EatChickenPlayer("b", 6000L);
        EatChickenPlayer c = new EatChickenPlayer("c", 9000L);
        EatChickenPlayer d = new EatChickenPlayer("d", 4000L);
        a.start();
        b.start();
        c.start();
        d.start();
    }


    @SuppressWarnings("AlibabaAvoidUseTimer")
    private static class EatChickenPlayer extends Thread {
        /**
         * 玩家
         */
        private String name;

        /**
         * 下班时间
         */
        private Long offWorkTime;

        EatChickenPlayer(String name, Long time) {
            this.name = name;
            this.offWorkTime = time;
        }

        @Override
        public void run() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println(name + ":我上号了");
                    try {
                        barrier.await();
                        System.out.println(name + ":开打开打");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, offWorkTime);
        }
    }

}
